	/*
	 * Analyze.java
	 * 
	 * Handles the generation of data to be used by Play.java
	 * 
	 */

	/*
	 * Copyright (c) 2011 by Ryan Nikolaidis
	 * All rights reserved.
	 *
	 */

public class Generation {
	public static Integer[] genRhythmStatic(int numDur, int Dur)
	{
		Integer[] rhythm = new Integer[numDur];
		for (int i=0;i<numDur;i++)
		{
			rhythm[i]=Dur;
		}
		return rhythm;
	}
	
	public static Integer[] genScale(int startPch, int length, int scaleRoot, int scale, boolean directionUp )
	{
		Integer[] scalePchs= new Integer[length];
		int[] scalePchClasses = Constants.scales[scale];
		if (scaleRoot>0)
		{
			scalePchClasses = reorderScale(scaleRoot, scale);
		}
		scalePchs[0]=startPch;
		if (directionUp)
		{
			for (int i=1;i<scalePchs.length;i++)
			{
				scalePchs[i] = nextHighestInScale(scalePchs[i-1],scalePchClasses);
			}
		}
		else
		{
			for (int i=1;i<scalePchs.length;i++)
			{
				scalePchs[i] = nextLowestInScale(scalePchs[i-1],scalePchClasses);
			}
		}
		return scalePchs;
	}
	
	public static Integer[] genArp(int startPch, int length, int chordRoot, int chord, boolean directionUp )
	{
		Integer[] chordPchs= new Integer[length];
		int[] chordPchClasses = Chords.toChord(chord);
		
		for (int i=0;i<chordPchClasses.length;i++)
		{
			System.out.println("chordPchClasses "+chordPchClasses[i]);
		}
		if (chordRoot>0)
		{
			chordPchClasses = reorderChord(chordRoot, chordPchClasses);
		}
		chordPchs[0]=startPch;
		if (directionUp)
		{
			for (int i=1;i<chordPchs.length;i++)
			{
				chordPchs[i] = nextHighestInScale(chordPchs[i-1],chordPchClasses);
			}
		}
		else
		{
			for (int i=1;i<chordPchs.length;i++)
			{
				chordPchs[i] = nextLowestInScale(chordPchs[i-1],chordPchClasses);
			}
		}
		return chordPchs;
	}

	public static int approachTone(int target, int lastPch)
	{
		System.out.println("target tone = "+target);
		System.out.println("lastPch = "+lastPch);
		int AT = 0;
		
		if (Math.random()<Main.stats.approachToneDiatonic)
		{
//			diatonic approach tone
			if (lastPch>target)
			{
//				test if target +1 is diatonic
				if (noteInScale(target+2,makeScaleMajorMinor(Main.score.key,!Main.score.isMinor))&&lastPch%12!=((target%12)+2)%12)
				{
					AT = (target%12+2)%12;
				}
				else
				{
					AT = (target%12+1)%12;
				}
			}
			else
			{
				if (noteInScale(AltMath.mod(target-2,12),makeScaleMajorMinor(Main.score.key,!Main.score.isMinor))&&lastPch%12!=AltMath.mod(target-2,12)&&lastPch%12!=((target%12)+1)%12)
				{
					AT = AltMath.mod(target-2,12);
				}
				else
				{
					AT = AltMath.mod(target-1,12);
				}
			}
		}
		else
		{
//			chromatic approach tone
			if (lastPch>target&&lastPch%12!=((target%12)+1)%12)
			{
				AT = ((target%12)+1)%12;
			}
			else
			{
				AT = AltMath.mod(((target%12)-1),12);
			}
		}
//		System.out.println("AT = "+AT);
//		System.out.println("lastPch = "+lastPch);
		AT = nearestAbs(AT, lastPch);
//		System.out.println("new AT = "+AT);		
		return AT;
	}
	
	public static int nearestAbs(int pitchClass, int target) //output the nearest absolute pitch of pitchClass to target
	{
		int newNote = 0;
		int difference = 128;
		
		for (int i=1;i<12;i++)
		{
//			System.out.println("i = "+i+" (pitchClass+i*12)"+(pitchClass+i*12)+" Math.abs(target-(pitchClass+i*12)) = "+Math.abs(target-(pitchClass+i*12)));
			if (Math.abs(target-(pitchClass+i*12))<difference)
			{
				newNote = pitchClass+i*12;
				difference = Math.abs(target-(pitchClass+i*12));
			}
		}
		
		return newNote;
	}
	
	public static int nearestOctave(int pitchClass, int target) //output the nearest absolute pitch of pitchClass to target
	{
		int newNote = 0;
		int difference = 128;
		
		for (int i=1;i<12;i++)
		{
//			System.out.println("i = "+i+" (pitchClass+i*12)"+(pitchClass+i*12)+" Math.abs(target-(pitchClass+i*12)) = "+Math.abs(target-(pitchClass+i*12)));
			if (Math.abs(target-(pitchClass+i*12))<difference)
			{
				newNote = pitchClass+i*12;
				difference = Math.abs(target-(pitchClass+i*12));
			}
		}
		
		return 12*((int)(newNote/12));
	}
	public static int[] reorderScale(int scaleRoot, int scale)
	{
		int[] scaleArray = new int[Constants.scales[scale].length];
		int indexMin = 0;
		for (int i=0;i<Constants.scales[scale].length;i++)
		{
			scaleArray[i] = (Constants.scales[scale][i]+scaleRoot)%12;
//			find min
			if (i>0&&scaleArray[i]<scaleArray[i-1])
			{
				indexMin=i;
			}
		}
		int[] reorderedScale = new int[scaleArray.length];
		for (int i=0;i<scaleArray.length;i++)
		{

			reorderedScale[i]=scaleArray[(indexMin+i)%scaleArray.length];
//			System.out.println("index = "+i+" reordered = "+reorderedScale[i]);
		}
//		int[] newScale = new int[Constants.scales[scale].length];
		return reorderedScale;
	}
	public static int[] reorderChord(int chordRoot, int[] chord)
	{
		int[] chordArray = new int[chord.length];
		int indexMin = 0;
		for (int i=0;i<chord.length;i++)
		{
			chordArray[i] = (chord[i]+chordRoot)%12;
//			find min
			if (i>0&&chordArray[i]<chordArray[i-1])
			{
				indexMin=i;
			}
//			System.out.println("chordArray = "+chordArray[i]);
		}
		int[] reorderedchord = new int[chordArray.length];
		for (int i=0;i<chordArray.length;i++)
		{

			reorderedchord[i]=chordArray[(indexMin+i)%chordArray.length];
//			System.out.println("index = "+i+" reordered = "+reorderedchord[i]);
		}
//		int[] newchord = new int[Constants.chords[chord].length];
		return reorderedchord;
	}
	
//	if you need to test something against the major or minor scale
	public static int[] makeScaleMajorMinor(int key, boolean keyMajor)
	{
		int[] scale=new int[Constants.scales[Constants.ionian].length];
		if (keyMajor)
			for (int i=0;i<Constants.scales[Constants.ionian].length;i++)
			{
				scale[i]=(Constants.scales[Constants.ionian][i]+key)%12;
			}
		else
		{
			for (int i=0;i<Constants.scales[Constants.aeolian].length;i++)
			{
				scale[i]=(Constants.scales[Constants.aeolian][i]+key)%12;
			}
		}
		return scale;
	}
//	 is a certain note in the current key / scale
	public static boolean noteInScale(int pitch, int[] scale) 
	{
		boolean inScale = false;
		for (int i=0;i<scale.length;i++)
		{
			if (pitch%12==scale[i])
			{
				inScale=true;
			}
		}
		
		return inScale;
	}
	public static int nextHighest(int lastPch, int nextPchClass)
	{
		if (nextPchClass<lastPch%12)
		{
			nextPchClass=nextPchClass+12;
		}
		int nextPch = lastPch+(nextPchClass-lastPch%12);
		return nextPch;
	}
	public static int nextLowest(int lastPch, int nextPchClass)
	{
		if (nextPchClass>lastPch%12)
		{
			nextPchClass=nextPchClass-12;
		}
		int nextPch = lastPch-(lastPch%12-nextPchClass);
		return nextPch;
	}
	public static int nextHighestInScale(int lastPch, int[] scale)
	{
		int note = scale[0]; 	// since it defaults to first (lowest) scale pitch class, 
								// if lastPch is less than this first scale degree ... 
								// then first scale degree is next highest
		int minDistance = 99;
		for (int i=0;i<scale.length;i++)
		{
			if ((scale[i]%12-lastPch%12)>0&&(scale[i]%12-lastPch%12)<minDistance)
			{
				minDistance=(scale[i]%12-lastPch%12);
				note = scale[i];
			}
		}
		note = nextHighest(lastPch,note);
		return note;
	}
	public static int nextLowestInScale(int lastPch, int[] scale)
	{
		int note = scale[scale.length-1]; 	// since it defaults to last (highest) scale pitch class, 
											// if lastPch is less than the first scale degree ... 
											// then last scale degree is next lowest
		int minDistance = 99;
		for (int i=0;i<scale.length;i++)
		{
			if ((lastPch%12-scale[i]%12)>0&&(lastPch%12-scale[i]%12)<minDistance)
			{
				minDistance=(lastPch%12-scale[i]%12);
				note = scale[i];
			}
		}
		note = nextLowest(lastPch,note);
		return note;
	}
}
